// ============================================================================
//
// Graph framework by Aurelien Moreau aurelien.moreau@gmail.com
// Modified by Pierre CHATEL chatelp@gmail.com
// Distributed under LGPL
// Copyright (C) Aurelien Moreau, 2008, 2009. All rights reserved
//
// ============================================================================

package com.thalesgroup.graphFramework.collections;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;


public class MapSet<T, V> extends HashMap<T, Set<V>> {

	private static final long serialVersionUID = 6921490071338619554L;

	public MapSet() {
		super();
	}

	public MapSet(final MapSet<T, V> mapSet) {
		super(mapSet);
		for (final Map.Entry<T, Set<V>> e : entrySet()) {
			final Set<V> nSet = new HashSet<V>(e.getValue());
			e.setValue(nSet);
		}
	}

	@Override
	public Object clone() {
		final MapSet<T, V> o = (MapSet<T, V>) super.clone();
		for (final Map.Entry<T, Set<V>> e : entrySet()) {
			final Set<V> nSet = new HashSet<V>(e.getValue());
			e.setValue(nSet);
		}
		return o;
	}

	public boolean add(final T key, final V value) {
		Set<V> set = get(key);
		if (set == null) {
			set = new HashSet<V>();
			put(key, set);
		}
		return set.add(value);
	}

	public boolean remove(final T key, final V value) {
		final Set<V> set = get(key);
		if (set == null) {
			return false;
		}
		final boolean present = set.remove(value);

		if (set.isEmpty()) {
			remove(key);
		}

		return present;
	}

	public void clusterize(final Iterable<? extends V> set,
			final Accessor<T, V> accessor) {
		clusterize(set.iterator(), accessor);
	}

	public void clusterize(final Iterator<? extends V> i,
			final Accessor<T, V> accessor) {
		for (; i.hasNext();) {
			final V element = i.next();
			final T cluster = accessor.cluster(element);
			add(cluster, element);
		}
	}

	public boolean addAll(final T key, final Collection<? extends V> values) {
		Set<V> set = get(key);
		boolean result = false;
		if (set == null) {
			set = new HashSet<V>(values.size());
			put(key, set);
			result = true;
		}
		set.addAll(values);
		return result;
	}

	public static <X, Y> MapSet<X, Y> newCluster(
			final Iterable<? extends Y> set, final Accessor<X, Y> accessor) {
		return newCluster(set.iterator(), accessor);
	}

	public static <X, Y> MapSet<X, Y> newCluster(
			final Iterator<? extends Y> set, final Accessor<X, Y> accessor) {
		if (set == null) {
			return null;
		}
		final MapSet<X, Y> mset = new MapSet<X, Y>();
		mset.clusterize(set, accessor);
		return mset;
	}
}
